using System;
using System.Net;
using System.Net.Sockets;
using xxpl1.Log;

namespace xxpl1.Proxy
{
    public abstract class Listener
    {
        private static readonly ILog logger = LogManager.GetLogger(typeof(Listener));
        protected readonly int port;
        protected Socket listenSocket;
        protected bool isRunning;

        public int Port
        {
            get { return port; }
        }

        public Socket ListenSocket
        {
            get { return listenSocket; }
        }

        public bool IsRunning
        {
            get { return isRunning; }
        }

        protected Listener(int port)
        {
            this.port = port;
        }

        public void Start()
        {
            try
            {
                listenSocket = new Socket(IPAddress.Loopback.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, port));
                listenSocket.Listen(-1);
                listenSocket.BeginAccept(OnNewConnection, listenSocket);
                isRunning = true;
            }
            catch (Exception e)
            {
                logger.Error("Start listener failed:", e);
                isRunning = false;
            }
        }

        public void Stop()
        {
            isRunning = false;
            listenSocket.Close();
        }

        private void OnNewConnection(IAsyncResult ar)
        {
            OnAccept(ar);

            WaitNextRequest(ar);
        }

        private void WaitNextRequest(IAsyncResult ar)
        {
            if (!isRunning)
                return;

            try
            {
                listenSocket.BeginAccept(OnNewConnection, listenSocket);
            }
            catch (Exception e)
            {
                isRunning = false;
                logger.Error("Listen socket failed:", e);
            }
        }

        public abstract void OnAccept(IAsyncResult ar);
    }
}